package com.gopay.checkorder.service.task.self;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BisBankOrderQueryDAO;
import com.gopay.checkorder.service.BankOrderService;
import com.gopay.checkorder.service.alarm.OrderAlarmDataCollector;
import com.gopay.checkorder.service.alarm.OrderAlarmRecordStorage;
import com.gopay.checkorder.service.task.Task;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.bank.BankOrderType;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.cps.vo.CheckOrderResult;
import com.gopay.common.order.dao.CommonQueryDAO;
import com.gopay.common.util.DateUtils;

public class IcbcCheckOrderByKeyTaskImpl implements Task {

	private final static Logger logger = LoggerFactory.getLogger("CHECK_ORDER");


	@Resource(name = "bisBankOrderQueryDAO")
	private BisBankOrderQueryDAO bisBankOrderQueryDAO;

	@Resource(name = "bankOrderService")
	private BankOrderService bankOrderService;

	@Resource(name = "orderAlarmRecordStorage")
	private OrderAlarmRecordStorage orderAlarmRecordStorage;
	
	@Resource(name = "commonQueryDAO")
    private CommonQueryDAO commonQueryDAO;
	
	private String BANK = "ICBC";
	private String label;
	private int remainder;
    private int modInt;
    private long taskCounter = 0;
    private long b2bRate;
	/**
	 * 银行流水状态
	 */
	private String orderStatus;

	private void printLog(StopWatch sw, String bank, String orderStatus,
			String prefix) {
		sw.split();
		logger.error("label_" + label + "工行对账task" + prefix + "------,bank=" + BANK + ",orderStatus="
				+ orderStatus + ",耗时=" + sw.getSplitTime());
	}

	/**
	 * 任务执行
	 */
    public void doTask() {
        try {
            StopWatch sw = new StopWatch();
            sw.start();
            printLog(sw, BANK, orderStatus, "IcbcCheckOrderByKeyTaskImpl------start");

            int pageSize = 180;
            int pageIndex = 1;

            checkBefore();

            List<BankOrder> list = getCheckOrder(orderStatus, pageIndex, pageSize);
            printLog(sw, BANK, orderStatus, "IcbcCheckOrderByKeyTaskImpl------list.size()=" + list.size() + ",pageIndex="
                    + pageIndex);

            // 订单对账报警采集者
            OrderAlarmDataCollector alarmCollector = new OrderAlarmDataCollector();

            for (BankOrder bankOrder : list) {
                try {
                    bankOrder.setRemark2(label); // ICBC对账请求label,标识对应前置机
                    alarmCollector.addTotal(bankOrder.getBankCode());

                    logger.error("label_"+label+"工行对账task--开始 ，orderId="+bankOrder.getOrderId()+",bank="+BANK);
                    CheckOrderResult checkResult = bankOrderService.checkOrder(bankOrder,
                            BankOrderStatus.AUTO_CHECK_SUCCESS);
                    logger.error("label_"+label+"工行对账task--结束 ，orderId="+bankOrder.getOrderId()+",bank="+BANK);

                    if (checkResult != null && checkResult.isCommunicateError() == true) {
                        logger.error("IcbcCheckOrderByKeyTask checkResult  communicateError-----------" + checkResult.isCommunicateError());
                        alarmCollector.addFail(bankOrder.getBankCode());
                        logger.error("IcbcCheckOrderByKeyTask checkResult  fail*****" + alarmCollector.getFail(bankOrder.getBankCode()));
                        logger.error("IcbcCheckOrderByKeyTask checkResult  total****" + alarmCollector.getTotal(bankOrder.getBankCode()));
                    }
                } catch (Exception e) {
                    logger.info("---------- IcbcCheckOrderByKeyTask对单error---------", e);
                }
            }
            // 判断报警阈值并保存报警记录
            orderAlarmRecordStorage.store(alarmCollector);

            printLog(sw, BANK, orderStatus, "IcbcCheckOrderByKeyTaskImpl------end");
            sw.stop();

        } catch (Throwable t) {
            logger.error("IcbcCheckOrderByKey执行对单Task时出现异常", t);
        }
    }

	/**
     * 
     */
	private void checkBefore() {
	}

    /**
     * 分页查询工行对账记录
     * 
     * @param orderStatus
     * @param totalCheckTimes
     * @param pageIndex
     * @param pageSize
     * @return
     */
    protected List<BankOrder> getCheckOrder(String orderStatus, int pageIndex, int pageSize) {
        if (isCheckB2bOrders()) {
            // 获取B2B对单记录
            List<BankOrder> b2bList = getCheckB2bOrder(new Date(), pageIndex, pageSize);
            int remaindCount = pageSize - b2bList.size(); // 除去B2B订单，剩余对单数量
            if (remaindCount > 0) {
                // 获取B2C对单记录
                List<BankOrder> b2cList = getCheckB2cOrderByBank(orderStatus,modInt,remainder,pageIndex, remaindCount);
                b2bList.addAll(b2cList);
            }
            return b2bList;
        } else {
            // 获取B2C对单记录
            return getCheckB2cOrderByBank(orderStatus,modInt,remainder,pageIndex, pageSize);
        }
    }
	
    /**
     * 是否执行ICBC B2B查询定时任务
     * 
     * @return
     */
    private Boolean isCheckB2bOrders() {
        if (b2bRate == 0) {
            return false;
        }
        taskCounter++;
        if (taskCounter % b2bRate == 0) {
            return true;
        }
        return false;
    }
	
    /**
     * 查询ICBC B2B对账记录
     * 
     * @param date
     * @param pageIndex
     * @param pageSize
     * @return
     */
    protected List<BankOrder> getCheckB2bOrder(Date date, int pageIndex, int pageSize){
        Map<String, Object> params = new HashMap<String, Object>();
        
        StringBuilder sb=new StringBuilder();
        sb.append(buildHqlAndParamsOfCorpB2B(params));
        sb.append(" order by totalCheckTimes asc ");

        return bisBankOrderQueryDAO.findByHql(sb.toString(), params, pageIndex, pageSize);
    }
	
    /**
     * 查询ICBC B2C对账记录
     * 
     * @param orderStatus
     * @param modInt
     * @param remainder
     * @param pageIndex
     * @param pageSize
     * @return
     */
	private List<BankOrder> getCheckB2cOrderByBank(String orderStatus, int modInt, int remainder, int pageIndex, int pageSize){
	    StringBuilder sql = buildQueryReturnFields();
	    sql.append(" where 1=1 ");
        sql.append(" and t.ORDER_TYPE = :orderType ");        
        sql.append(" and t.TOTAL_CHECK_TIMES <7 ");
        sql.append(" and t.ORDER_STATUS = :orderStatus ");
        // edit hougn 2017-08-01 09改为00  start
        //sql.append(" and t.BANK_BIZ_PROD_CODE != :bankBizProdCode ");
        sql.append(" and t.BANK_BIZ_PROD_CODE not in ('01','09') ");
        // edit hougn 2017-08-01 end
        sql.append(" and t.GOPAY_BANK_CODE = :bankCode ");
        sql.append(buildBeginEndTimeClauseOfSQL());
        
        if(modInt!=1){
            sql.append(" and mod(t.GOPAY_ORDER_ID,:modInt)=:remainder ");
        }
        sql.append(" order by t.TOTAL_CHECK_TIMES asc,t.GOPAY_ORDER_ID asc ");
        
        //param
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("orderType", BankOrderType.GOPAY_BIS_ORDER);
        params.put("orderStatus", orderStatus);
        // edit hougn 2017-08-01 09改为00  start
        //params.put("bankBizProdCode", BisBankBusinessProd._09.value);
        // edit hougn 2017-08-01  end 
        params.put("bankCode", BANK);
        if(modInt!=1){
            params.put("modInt", modInt);
            params.put("remainder", remainder);
        }

        List<Object[]> list = commonQueryDAO.findBySql(sql.toString(), params, pageIndex, pageSize);
        return buildQueryResult(list);
    }
	
	private String buildHqlAndParamsOfCorpB2B(Map<String, Object> params){
        StringBuffer hql = new StringBuffer("");
        hql.append(" from BankOrder ");
        hql.append(" where orderStatus in (:orderStatus00,:orderStatus92)  ");
        hql.append(" and bankBizProdCode = :bankBizProdCode  ");
        hql.append(" and orderType = :orderType ");   
        hql.append(" and bankCode = :bankCode ");   
        hql.append(" and sendBankTm >to_date(:beginTime,'yyyyMMddHH24miss') ");
        
        //map        
        params.put("orderStatus00", BankOrderStatus.PROCESS);
        params.put("orderStatus92", BankOrderStatus.VERIFY_FAIL);
        //去掉对账96入账失败状态
       // params.put("orderStatus96", BankOrderStatus.ENTER_ACCOUNT_FIAL);
        params.put("bankBizProdCode", BisBankBusinessProd._01.value);
        params.put("orderType", BankOrderType.GOPAY_BIS_ORDER);
        params.put("bankCode", BANK);
        
        //开始时间--最近20天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -20);
        params.put("beginTime",DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss"));
        
        return hql.toString();
    }
    
    private StringBuilder buildQueryReturnFields(){
        StringBuilder sql = new StringBuilder("select /*+ INDEX(t IDX_BANK_STATUS_TM) */ ");
        sql.append(" t.GOPAY_OUT_ORDER_ID, ");
        sql.append(" t.GOPAY_BANK_CODE ");
        sql.append(" from BIS_BANK_MAIN_ORDER t ");
        
        return sql;
    }
    
    private String buildBeginEndTimeClauseOfSQL(){
        Calendar calendar = Calendar.getInstance();
        //开始时间--最近一天
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        String beginTime=DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss");
        
        //截至时间--90秒前
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND, -90);
        String endTime=DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss");
        
        StringBuilder sb=new StringBuilder(" and t.SEND_BANK_TM <to_date('"+endTime+"','yyyyMMddHH24miss')");
        sb.append(" and t.SEND_BANK_TM >to_date('"+beginTime+"','yyyyMMddHH24miss')");
        return sb.toString();
    }
    
    private List<BankOrder> buildQueryResult(List<Object[]> rsList){
        List<BankOrder> orderList=new ArrayList<BankOrder>();

        String orderId;
        for (Object[] arr : rsList) {
            orderId=(String) arr[0];
            if(StringUtils.isNotBlank(orderId)){
                orderList.add(bisBankOrderQueryDAO.find(BankOrder.class, orderId));
            }
        }
        
        return orderList;
    }

	public void setOrderStatus(String orderStatus) {
		this.orderStatus = orderStatus;
	}
	public void setRemainder(int remainder) {
        this.remainder = remainder;
    }

    public void setModInt(int modInt) {
        this.modInt = modInt;
    }

	public void setLabel(String label) {
		this.label = label;
	}

	public void setB2bRate(long b2bRate) {
		this.b2bRate = b2bRate;
	}

}
